use ash::vk::{self, CommandBufferUsageFlags, CommandBuffer};
use crate::{vulkan::{VkContext, vk_struct::QueueType, vk_utils::utils_info}, VK_CHECK};

impl VkContext {
    fn get_command_buffer_ai(&self) -> vk::CommandBufferAllocateInfo {
        vk::CommandBufferAllocateInfo {
            s_type                  : vk::StructureType::COMMAND_BUFFER_ALLOCATE_INFO,
            p_next                  : std::ptr::null(),
            command_pool            : self.vk_command_pool,
            level                   : vk::CommandBufferLevel::PRIMARY,
            // command_buffer_count    : command_buffer_count

            ..Default::default()
        }
    }

    fn get_command_buffer_bi(&self) -> vk::CommandBufferBeginInfo {
        vk::CommandBufferBeginInfo {
            s_type                  : vk::StructureType::COMMAND_BUFFER_BEGIN_INFO,
            p_next                  : std::ptr::null(),
            // flags                   : CommandBufferUsageFlags::ONE_TIME_SUBMIT, // important
            p_inheritance_info      : std::ptr::null(),

            ..Default::default()
        }
    }

    pub fn create_command_buffers(&self, command_buffer_count: usize) -> Vec<vk::CommandBuffer> {
        let mut command_buffer_ai = self.get_command_buffer_ai();
        command_buffer_ai.command_buffer_count = command_buffer_count as u32;

        let command_buffers = match VK_CHECK!(unsafe {self.vk_device.allocate_command_buffers(&command_buffer_ai)}) {
            Some(inner_value) => inner_value,
            None => vec![]
        };

        command_buffers
    }

    pub fn begin_single_time_commands(&self) -> CommandBuffer {
        // Start Command
        let command_buffer = self.create_command_buffers(1)[0];
        let mut command_buffer_bi = self.get_command_buffer_bi();
        command_buffer_bi.flags = CommandBufferUsageFlags::ONE_TIME_SUBMIT;

        VK_CHECK!(unsafe {self.vk_device.begin_command_buffer(command_buffer, &command_buffer_bi)} );

        command_buffer
    }

    pub fn end_single_time_commands(&self, command_buffer: CommandBuffer) {
        // End Command
        VK_CHECK!(unsafe {self.vk_device.end_command_buffer(command_buffer)} );

        // Submit Info
        let command_buffers = [command_buffer];
        let mut submit_info = utils_info::get_submit_info();
        submit_info.command_buffer_count    = command_buffers.len() as u32;
        submit_info.p_command_buffers       = command_buffers.as_ptr();

        let vk_queue = self.get_vk_queue(QueueType::GTC);
        VK_CHECK!(unsafe {self.vk_device.queue_submit(vk_queue.handler, &[submit_info], vk::Fence::null())} );
        VK_CHECK!(unsafe {self.vk_device.queue_wait_idle(vk_queue.handler)} );
        unsafe {self.vk_device.free_command_buffers(self.vk_command_pool, &command_buffers)};
    }
}